Kotlin
Higher-Order Functions and Lambdas
Swift
|
Higher-Order Functions
|
fun <T, R> Collection<T>.fold(
initial: R,
combine: (acc: R, nextElement: T) -> R
): R {
var accumulator: R = initial
for (element: T in this) {
accumulator = combine(accumulator, element)
}
return accumulator
}
|
func <T, R> Collection<T>.fold(
initial: R,
combine: (acc: R, nextElement: T) -> R
): R {
var accumulator: R = initial
for (element: T in this) {
accumulator = combine(accumulator, element)
}
return accumulator
}
|
val items = listOf(1, 2, 3, 4, 5)
// Lambdas are code blocks enclosed in curly braces.
items.fold(0, {
// When a lambda has parameters, they go first, followed by '->'
acc: Int, i: Int ->
print("acc = $acc, i = $i, ")
val result = acc + i
println("result = $result")
// The last expression in a lambda is considered the return value:
result
})
// Parameter types in a lambda are optional if they can be inferred:
val joinedToString = items.fold("Elements:", { acc, i -> acc + " " + i })
// Function references can also be used for higher-order function calls:
val product = items.fold(1, Int::times)
|
let items = [1, 2, 3, 4, 5]
// Lambdas are code blocks enclosed in curly braces.
items.fold(0, {
// When a lambda has parameters, they go first, followed by '->'
acc: Int, i: Int ->
print("acc = $acc, i = $i, ")
let result = acc + i
print("result = $result")
// The last expression in a lambda is considered the return value:
result
})
// Parameter types in a lambda are optional if they can be inferred:
let joinedToString = items.fold("Elements:", { acc, i -> acc + " " + i })
// Function references can also be used for higher-order function calls:
let product = items.fold(1, Int::times)
|
Function types
|
typealias ClickHandler = (Button, ClickEvent) -> Unit
|
typealias ClickHandler = (Button, ClickEvent) -> Unit
|
Instantiating a function type
|
class IntTransformer: (Int) -> Int {
override operator fun invoke(x: Int): Int = TODO()
}
val intFunction: (Int) -> Int = IntTransformer()
|
class IntTransformer: (Int) -> Int {
override operator func invoke(x: Int) -> Int = TODO()
}
let intFunction: (Int) -> Int = IntTransformer()
|
val a = { i: Int -> i + 1 } // The inferred type is (Int) -> Int
|
let a = { i: Int -> i + 1 } // The inferred type is (Int) -> Int
|
val repeatFun: String.(Int) -> String = { times -> this.repeat(times) }
val twoParameters: (String, Int) -> String = repeatFun // OK
fun runTransformation(f: (String, Int) -> String): String {
return f("hello", 3)
}
val result = runTransformation(repeatFun) // OK
|
let repeatFun: String.(Int) -> String = { times -> this.repeat(times) }
let twoParameters: (String, Int) -> String = repeatfunc // OK
func runTransformation(f: (String, Int) -> String) -> String {
return f("hello", 3)
}
let result = runTransformation(repeatFun) // OK
|
Invoking a function type instance
|
val stringPlus: (String, String) -> String = String::plus
val intPlus: Int.(Int) -> Int = Int::plus
println(stringPlus.invoke("<-", "->"))
println(stringPlus("Hello, ", "world!"))
println(intPlus.invoke(1, 1))
println(intPlus(1, 2))
println(2.intPlus(3)) // extension-like call
|
let stringPlus: (String, String) -> String = String::plus
let intPlus: Int.(Int) -> Int = Int::plus
print(stringPlus.invoke("<-", "->"))
print(stringPlus("Hello, ", "world!"))
print(intPlus.invoke(1, 1))
print(intPlus(1, 2))
print(2.intPlus(3)) // extension-like call
|
Lambda Expressions and Anonymous Functions
|
max(strings, { a, b -> a.length < b.length })
|
max(strings, { a, b -> a.length < b.length })
|
fun compare(a: String, b: String): Boolean = a.length < b.length
|
func compare(a: String, b: String): Boolean = a.length < b.length
|
Lambda expression syntax
|
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
|
let sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
|
val sum = { x: Int, y: Int -> x + y }
|
let sum = { x: Int, y: Int -> x + y }
|
Passing trailing lambdas
|
val product = items.fold(1) { acc, e -> acc * e }
|
let product = items.fold(1) { acc, e -> acc * e }
|
run { println("...") }
|
run { print("...") }
|
it: implicit name of a single parameter
|
ints.filter { it > 0 } // this literal is of type '(it: Int) -> Boolean'
|
ints.filter { $0 > 0 } // this literal is of type '(it: Int) -> Boolean'
|
Returning a value from a lambda expression
|
ints.filter {
val shouldFilter = it > 0
shouldFilter
}
ints.filter {
val shouldFilter = it > 0
return@filter shouldFilter
}
|
ints.filter {
let shouldFilter = $0 > 0
shouldFilter
}
ints.filter {
let shouldFilter = $0 > 0
return@filter shouldFilter
}
|
strings.filter { it.length == 5 }.sortedBy { it }.map { it.toUpperCase() }
|
strings.filter { it.length == 5 }.sortedBy { $0 }.map { it.toUpperCase() }
|
Underscore for unused variables (since 1.1)
|
map.forEach { _, value -> println("$value!") }
|
map.forEach { _, value -> print("$value!") }
|
Anonymous functions
|
fun(x: Int, y: Int): Int = x + y
|
fun(x: Int, y: Int) -> Int = x + y
|
fun(x: Int, y: Int): Int {
return x + y
}
|
fun(x: Int, y: Int) -> Int {
return x + y
}
|
ints.filter(fun(item) = item > 0)
|
ints.filter(fun(item) = item > 0)
|
Closures
|
var sum = 0
ints.filter { it > 0 }.forEach {
sum += it
}
print(sum)
|
var sum = 0
ints.filter { $0 > 0 }.forEach {
sum += it
}
print(sum)
|
Function literals with receiver
|
val sum: Int.(Int) -> Int = { other -> plus(other) }
|
let sum: Int.(Int) -> Int = { other -> plus(other) }
|
val sum = fun Int.(other: Int): Int = this + other
|
let sum = func Int.(other: Int) -> Int = this + other
|
class HTML {
fun body() { ... }
}
fun html(init: HTML.() -> Unit): HTML {
val html = HTML() // create the receiver object
html.init() // pass the receiver object to the lambda
return html
}
html { // lambda with receiver begins here
body() // calling a method on the receiver object
}
|
class HTML {
func body() { ... }
}
func html(init: HTML.() -> Unit): HTML {
let html = HTML() // create the receiver object
html.init() // pass the receiver object to the lambda
return html
}
html { // lambda with receiver begins here
body() // calling a method on the receiver object
}
|